技巧18 在构建时引用特定的镜像

在构建过程中绝大部分时间里所引用的将是一些通用的镜像名,如“node”或“ubuntu”,而且这些用起来可能不会有问题。

如果引用的是一个镜像名,该镜像有可能会在标签保持不变的情况下发生变化。尽管听起来很荒谬,但是的确是这样的!仓库的名字只是一个引用,而它所指向的底层镜像可能会变成不同的。用冒号指定一个标签(如 ubuntu:trusty )也没办法消除这一风险,因为像一些安全更新就可以用相同的标签自动地重新构建易受攻击的镜像。

绝大多数时候用户可能是希望这样的——镜像的维护人员可能找到了一个改进以及修补安全漏洞的方法,这通常是一件好事。不过有时候这也会是一个痛点。而这不只是一个理论上的风险:在一些场合下已经发生了这样的事情,它以一种难以调试的方式破坏了持续交付的构建。在Docker发展初期,那些最受欢迎的镜像会定期地添加和删除软件包(这里面还包括一个令人难忘的回忆, passwd 命令居然消失了!),造成之前还正常工作的构建突然崩掉。

问题

想要确保是从一个特定的未做更改的镜像构建。

解决方案

要绝对地确定构建时使用的是给定的文件时,可以在Dockerfile里指定一个特定的镜像ID。

代码清单3-23中给出的是一个例子(可能在读者的环境里无法正常工作)。

代码清单3-23 一个指定镜像ID的Dockerfile

 FROM 8eaa4ff06b53  ⇽--- 从一个指定的镜像(或层)ID构建
 RUN echo "Built from image id:" > /etc/buildinfo  ⇽--- 
 RUN echo "8eaa4ff06b53" >> /etc/buildinfo
 RUN echo "an ubuntu 14.4.01 image" >> /etc/buildinfo  ⇽--- 在这个镜像里执行一个命令,把构建时引用的镜像记录到新镜像的一个文件里
 CMD ["echo","/etc/buildinfo"]  ⇽--- 构建的镜像默认会输出记录到/etc/buildinfo文件里的信息

要像这样从一个特定的镜像(或层)ID构建,镜像ID就必须存储到Docker守护进程本地。Docker注册中心将不会执行任何类型的查找操作来找出Docker Hub上可用镜像的各个层的镜像ID,也不会在可能配置使用的任何其他注册中心上这样做。

值得一提的是,用户指向的那个镜像是不需要打过标签的——它可以是本地的任意一个镜像层。用户可以从希望的任何层开始构建。这在做某些调查或一些实验性步骤而想要完成Dockerfile的构建分析时也许有用。

如果想远程持久化镜像,那么最好是给该镜像打上标签,然后将它推送到远程注册中心里一个受控制的仓库下。

警告

值得指出的是,绝大部分要面对的问题都发生在一个之前还工作的Docker镜像突然间就不工作了的时候。通常这是因为一些东西在网络层面有所变动。这其中一个记忆犹新的例子便是:某个早上我们的构建因为 apt-get update 失败。我们假定这是本地deb缓存的问题,然后尝试调试但是没有成功,直到一位可爱的系统管理员指出我们正在构建的这个特定版本的Ubuntu已经不再被支持了。这意味着 apt-get update 的网络调用都在返回HTTP错误。

讨论

尽管这听上去可能有点理论化,这里面的重点在于理解更特定地指定用户想要构建或运行的镜像这样做带来的利弊。

更确定的指定镜像可以让用户操作的结果更加符合预期也更易于调试,因为这里要下载或已经下载的Docker镜像不确定性更少。这样做的弊端在于用户镜像可能不是最新的,而且用户可能会因此错过重要的更新。用户更倾向于哪种做法取决于自身特定的用例场景以及用户需要在Docker环境下优先考虑的是哪些事项。

在3.3节里,用户将会运用所学知识玩一个有意思的实际例子:在2048里获胜。

results matching ""

    No results matching ""